

self.importScripts("common.js")
// 文件期待大小
var expectLength = 32 * 1024;
var data = null;



function Downloader() {
    this.logger = new Logger("Downloader");
    this.ws = null;
    this.data = null;
    this.heartInterval = null;
    this.sendInterval = null;
    this.pauseFlag = false;
    this.lastRecvTime = new Date();
    this.testWoker = null;
}

Downloader.prototype.appendBuffer = function (buffer1, buffer2) {
    let tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
    tmp.set(new Uint8Array(buffer1), 0);
    tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
    return tmp.buffer;
};

Downloader.prototype.reportFileSize = function (sz, st) {
    var objData = {
        t: kGetFileInfoRsp,
        i: {
            sz: sz,
            st: st
        }
    };

    //this.logger.logInfo("File size " + sz + " bytes.");
    self.postMessage(objData);
};

Downloader.prototype.reportData = function (start, end, seq, data) {
    var objData = {
        t: kFileData,
        s: start,
        e: end,
        d: data,
        q: seq
    };
    self.postMessage(objData, [objData.d]);
};

/**
 * 心跳检测，定时检测是否接受到了消息，没接收到要进行断线重连
 */
Downloader.prototype.receiveHeart = function () {
    
    if (this.heartInterval) {
      clearInterval(this.heartInterval);
      this.heartInterval = null;
    }
    
    var _self = this;
    
    _self.heartInterval = setInterval(function () {
      var currentTime = new Date().getTime()
      if (currentTime - _self.lastRecvTime > 10000 && !_self.pauseFlag) {
        var objData = {
          t: kWsReconnect
        };
        self.postMessage(objData);
        
        if (_self.heartInterval) {
          clearInterval(_self.heartInterval);
          _self.heartInterval = null;
        }
        
        
        if (_self.sendInterval) {
          clearInterval(_self.sendInterval);
          _self.sendInterval = null;
        }
        
      }
      // _self.logger.logError("Ws heart " + _self.receiveMessage);
    }, 10000)
}

/**
 * 定时发送心跳包给服务器, 避免服务器断开
 */
Downloader.prototype.sendHeart = function () {
    if (this.sendInterval) {
      clearInterval(this.sendInterval);
      this.sendInterval = null;
    }

    var _self = this;
    
		var heartValue = JSON.stringify({ msg: kHeartCommand, obj: null});

    _self.ws.send(heartValue);

    _self.sendInterval = setInterval(function () {
      // 发送心跳
      _self.ws.send(heartValue)
    }, 10000)
}

Downloader.prototype.seekTo = function (time) {
    if (this.ws) {
      var msg = JSON.stringify({ msg: kSeekCommand, obj: {time: time}})
      this.ws.send(msg)
    }
}

Downloader.prototype.pause = function (value) {
    this.pauseFlag = value ? true : false
    if (this.ws) {
      const msg = JSON.stringify({msg: kPauseCommand, obj: {pause: value}})
      this.ws.send(msg)
    }
}



Downloader.prototype.speed = function (value) {
    console.log('downloader speed', value)
    if (this.ws) {
      var msg = JSON.stringify({ msg: kSpeedCommand, obj: {speed: value}})
      this.ws.send(msg)
    }
}

Downloader.prototype.singleFrame = function () {
    console.log('downloader single Frame')
    if (this.ws) {
      var msg = JSON.stringify({ msg: kSingleFrameCommand, obj: null})
      this.ws.send(msg)
    }
}



// Websocket implement, NOTICE MUST call requestWebsocket serially, MUST wait
// for result of last websocket request(cb called) for there's only one stream
// exists.
Downloader.prototype.requestWebsocket = function (url, msg, cb) {
  if (this.ws == null) {
      var _self = this;
      this.ws = new WebSocket(url);
      this.ws.binaryType = 'arraybuffer';
      this.ws.onopen = function(evt) {
          _self.logger.logInfo("Ws connected.");
          var objData = {
            t: kWsSuccess
          }
          self.postMessage(objData)
          _self.receiveHeart()
          _self.sendHeart()
      };

      this.ws.onerror = function (evt) {
          _self.logger.logError("Ws connect error" + evt);
          var objData = {
            t: kWsError
          }
          self.postMessage(objData)
      }

      this.ws.onclose = function (evt) {
        _self.logger.logInfo("Ws connect close");
      }

      this.ws.onmessage = cb.onmessage;
  } else {
    this.ws.onmessage = cb.onmessage;
    
      // this.ws.send(msg);
  }
};


Downloader.prototype.downloadFileByWebsocket = function (url, start, end, seq) {
    //this.logger.logInfo("Downloading file " + url + ", bytes=" + start + "-" + end + ".");

    var cmd = {
        url : url,
        cmd : "data",
        start : start,
        end : end
    };

    var self = this

    this.requestWebsocket(url, JSON.stringify(cmd), {
        onmessage: function (evt) {
            if (evt.data) {
              self.data = evt.data
            }
            self.lastRecvTime = new Date().getTime()
            self.reportData(start, end, seq, self.data);
        }
    });
};

// Interface.
Downloader.prototype.getFileInfo = function (proto, url) {
    switch (proto) {
        case kProtoHttp:
            this.getFileInfoByHttp(url);
            break;
        case kProtoWebsocket:
            this.getFileInfoByWebsocket(url);
            break;
        default:
            this.logger.logError("Invalid protocol " + proto);
            break;
    }
};

Downloader.prototype.downloadFile = function (proto, url, start, end, seq) {
    switch (proto) {
        case kProtoHttp:
            this.downloadFileByHttp(url, start, end, seq);
            break;
        case kProtoWebsocket:
            this.downloadFileByWebsocket(url, start, end, seq);
            break;
        default:
            this.logger.logError("Invalid protocol " + proto);
            break;
    }
}

self.downloader = new Downloader();


self.addEventListener('message', (evt) => {
  if (!self.downloader) {
    console.log("[ER] Downloader not initialized!");
    return;
  }
  
  var objData = evt.data;
  switch (objData.t) {
      // case kGetFileInfoReq:
      //     self.downloader.getFileInfo(objData.p, objData.u);
      //     break;
      case kDownloadFileReq:
          self.downloader.downloadFile(objData.p, objData.u, objData.s, objData.e, objData.q);
          break;
      case kCloseDownloaderReq:
          closeWebsocket()
          break;
      case KPauseReq:
          self.downloader.pause(objData.p);
          break;
      case KContinueReq:
          self.downloader.continue();
          break;
      case KSeekToReq:
          self.downloader.seekTo(objData.s);
          break;
      case kSpeedReq:
          self.downloader.speed(objData.s);
          break;
      case kSingleFrameReq:
          self.downloader.singleFrame();
          break;
      default:
          self.downloader.logger.logError("Unsupport messsage " + objData.t);
          break;
  }
})


function closeWebsocket () {
  if (self.downloader && self.downloader.ws) {
    self.downloader.ws.close();
    // 为了解决火狐浏览器下的异常问题, onerror回调函数设置为空
    self.downloader.ws.onerror = null;
    self.downloader.ws = null;

    if (self.downloader.heartInterval) {
      clearInterval(self.downloader.heartInterval);
      self.downloader.heartInterval = null;
    }

    if (self.downloader.sendInterval) {
      clearInterval(self.downloader.sendInterval);
      self.downloader.sendInterval = null;
    }
  }
}
